--- 模块功能：MQTT客户端数据接收处理
-- @author openLuat
-- @module mqtt.mqttInMsg
-- @license MIT
-- @copyright openLuat
-- @release 2018.03.28
module(..., package.seeall)

require "earthquakeWaringDril"
require "eqtParaNvm"
require "sendDeviceLocation"
require "remoteTextBroadcast"
require "getDevStatus"
require "logGenerator"
require "utilsBySelf"
require "nvm"
require "earthquakeWaring"
require "logUploadHttp"
require "delGeneratorFlie"
require "networkTiming"
require "versionUpgrade"
require "registerTask"
require "deviceRestart"
require "deviceOnlineCheck"
require "batchSetParameters"
require "mqttOutMsg"

-- 参数配置文件初始化
nvm.init("config.lua", true)
-- 变量初始化
local clientNo, typeId, orgId, slen, errInfo, logInfo, sysTime, action,
      acountSuspend, regCenter = nvm.get("info")[1], nvm.get("info")[3],
                                 tonumber(nvm.get("info")[4]), string.len, "",
                                 "", "", false, 0, nvm.get("regCenter")

-- 预警演练设备身份判别
local function containClientsOrNot(equipment_clients)
    local containResult = false
    log.info("#equipment_clients", #equipment_clients)
    for i = 1, #equipment_clients do
        log.info("equipment_clients", equipment_clients[i], "clientNo", clientNo)
        if equipment_clients[i] == clientNo then containResult = true end
    end
    return containResult
end
-- 请求47.94.80.3:8080服务器获取单位信息
local function cbFnc(result, prompt, head, body)
    log.info("orgIdInfo.cbFnc", result, prompt)
    if result and head then
        for k, v in pairs(head) do
            log.info("orgIdInfo.cbFnc", k .. ": " .. v)
            sysTime = utilsBySelf.GetSystemTime()
            logInfo =
                logInfo .. "[" .. sysTime .. "]" .. "[orgIdInfo.cbFnc:]" .. k ..
                    ": " .. v .. "\n"
        end
    else
        sysTime = utilsBySelf.GetSystemTime()
        errInfo = errInfo .. "[" .. sysTime .. "]" ..
                      "[获取单位信息请求头错误！]\n"
    end
    if result and body then
        local tjsondataHttp, resultBody, errinfo = json.decode(body)
        log.info("orgIdInfo.cbFnc", "bodyLen=" .. body:len())
        log.info("body", body)
        if resultBody and type(tjsondataHttp) == "table" then
            local code, msg, data = tjsondataHttp["code"], tjsondataHttp["msg"],
                                    tjsondataHttp["data"]
            if data ~= nil and data ~= "" then
                if string.len(code) > 0 and string.len(msg) > 0 then
                    -- id:单位ID, longitude:经度, latitude:纬度, name:单位名称, city:城市, filter:云计算烈度过滤, centerName:中心名称, isCloud:是否云计算
                    -- upOrgId:上级Id, smsPhoneNum:短信通知手机号, ancestors:未知
                    local id, longitude, latitude, name, city, filter,
                          centerName, isCloud, upOrgId, smsPhoneNum, ancestors =
                        data["id"], data["longitude"], data["latitude"],
                        data["name"], data["city"], data["filter"],
                        data["centerName"], data["isCloud"], data["upOrgId"],
                        data["smsPhoneNum"], data["ancestors"]
                    if string.len(id) > 0 and string.len(name) > 0 and
                        string.len(city) > 0 and string.len(centerName) > 0 then
                        if longitude == "" or longitude == nil then
                            longitude = "0"
                        end
                        if latitude == "" or latitude == nil then
                            latitude = "0"
                        end
                        if filter == "" or filter == nil then
                            filter = "0"
                        end
                        if isCloud ~= "false" and isCloud ~= "true" then
                            isCloud = "false"
                        end
                        if smsPhoneNum == nil then
                            smsPhoneNum = ""
                        end
                        if ancestors == nil then
                            ancestors = ""
                        end
                        local sendMsg = "{\"code\":\"" .. code ..
                                            "\",\"msg\":\"" .. msg ..
                                            "\",\"data\":{\"id\":\"" .. id ..
                                            "\",\"longitude\":\"" .. longitude ..
                                            "\",\"latitude\":\"" .. latitude ..
                                            "\",\"name\":\"" .. name ..
                                            "\",\"city\":\"" .. city ..
                                            "\",\"filter\":\"" .. filter ..
                                            "\",\"centerName\":\"" .. centerName ..
                                            "\",\"isCloud\":\"" .. isCloud ..
                                            "\",\"upOrgId\":\"" .. upOrgId ..
                                            "\",\"smsPhoneNum\":\"" ..
                                            smsPhoneNum .. "\",\"ancestors\":\"" ..
                                            ancestors .. "\"}}"
                        local topicSendMqtt = "yunnan/orgInfo/set/" .. clientNo
                        sendMsg = crypto.aes_encrypt("ECB", "PKCS5", sendMsg,
                                                     "keson-123abcdefg")
                        sendMsg = crypto.base64_encode(sendMsg, slen(sendMsg))
                        mqttOutMsg.insertMsg(topicSendMqtt, sendMsg, 0)
                    else
                        sysTime = utilsBySelf.GetSystemTime()
                        errInfo = errInfo .. "[" .. sysTime .. "]" ..
                                      "[单位信息返回错误，必填字段返回空值：]单位Id:" ..
                                      id .. ",单位名称:" .. name ..
                                      ",城市:" .. city .. ",中心名称:" ..
                                      centerName .. ".\n"
                        logGenerator.generateLogTask(errInfo, "log")
                    end
                end
            end
        end
    else
        sysTime = utilsBySelf.GetSystemTime()
        errInfo = errInfo .. "[" .. sysTime .. "]" ..
                      "[获取单位信息请求体错误！]\n"
        logGenerator.generateLogTask(errInfo, "log")
    end
    log.info("getAndSetClientNo")
end

-- 主题是否包含判断
local function isContainTopic(topic)
    local containTopic = false
    local topicList = {}
    local centerNameList = string.split(nvm.get("centerName"), ",")
    for i = 1, #centerNameList, 1 do
        topicList[i] = "quake/" .. centerNameList[i]
        if topicList[i] == topic or "ZFH/KESON/TEST8622" == topic then
            containTopic = true
        end
    end
    return containTopic
end

--- MQTT客户端数据接收处理
-- @param mqttClient，MQTT客户端对象
-- @return 处理成功返回true，处理出错返回false
-- @usage mqttInMsg.proc(mqttClient)
function proc(mqttClient)
    local result, data, receiveMsg, base64DecodeMsg, aesDecryptMsg
    while true do
        sysTime = utilsBySelf.GetSystemTime()
        result, data = mqttClient:receive(60000, "APP_SOCKET_SEND_DATA")
        errInfo = ""
        -- 接收到数据
        if result then
            receiveMsg = data.payload
            base64DecodeMsg = crypto.base64_decode(receiveMsg, slen(receiveMsg))
            aesDecryptMsg = crypto.aes_decrypt("ECB", "PKCS5", base64DecodeMsg,
                                               "keson-123abcdefg")
            local tjsondata, resultMqtt, errinfo = json.decode(aesDecryptMsg)
            local clientsBool, todo, exercise, msgCode, unitId = false
            log.info("mqtt payload", aesDecryptMsg)
            log.info("data.topic", data.topic)
            if data.topic == "action/" .. typeId or data.topic == "action/" ..
                clientNo then
                log.info("errinfo：", errinfo)
                if resultMqtt and type(tjsondata) == "table" then
                    todo = tjsondata["todo"]
                    if tjsondata["clients"] then
                        clientsBool = containClientsOrNot(tjsondata["clients"])
                    end
                    if todo == "exercise" then
                        if clientsBool then
                            earthquakeWaringDril.EarthquakeWarningDrillSystem(
                                tjsondata, "keson","")
                        else
                            sysTime = utilsBySelf.GetSystemTime()
                            errInfo = errInfo .. "[" .. sysTime .. "]" ..
                                          "[设备号限制:]" ..
                                          "设备身份判别结果:" ..
                                          tostring(clientsBool) .. "\n"
                        end
                    elseif todo == "setConfig" then -- 存储远程修改的设备参数
                        if clientsBool then
                            sys.taskInit(eqtParaNvm.SaveParameters, tjsondata)
                        end
                    elseif todo == "readConfig" then -- 获取本地参数并上传到后端管理系统
                        eqtParaNvm.EquipmentParametersRead(tjsondata)
                    elseif todo == "gps" then -- 上传设备位置
                        if clientsBool then
                            sendDeviceLocation.seviceLocationSendTask(tjsondata)
                        end
                    elseif todo == "devStatus" then -- 获取设备状态
                        if clientsBool then
                            getDevStatus.getAndSaveDevStatus()
                        end
                    elseif todo == "broadcast" then -- 远程文本播报
                        if clientsBool then
                            remoteTextBroadcast.broadcastRemoteTextTask(
                                tjsondata)
                        end
                    elseif todo == "fetchAllLog" then -- 上传日志
                        if clientsBool then
                            logUploadHttp.uploadLogTask(tjsondata)
                        end
                    elseif todo == "clearAllLog" then -- 清除设备存储的所有日志文件
                        if clientsBool then
                            delGeneratorFlie.delAllExpiredFiles(tjsondata)
                        end
                    elseif todo == "synTime" then -- 手动授时
                        if clientsBool then
                            networkTiming.setNetworkTimingByManual(tjsondata)
                        end
                    elseif todo == "update" then -- 版本更新（设备重启）
                        if clientsBool then
                            sys.taskInit(versionUpgrade.deviceRestartUpgrade,
                                         tjsondata)
                        end
                    elseif todo == "register" then -- 手动注册
                        if clientsBool then
                            registerTask.RegistrationServiceTask()
                        end
                    elseif todo == "altertinfo" then -- 变更注册信息
                        if clientsBool then
                            registerTask.ChangeRegistrationInfoServiceTask()
                        end
                    elseif todo == "suspend" then -- 授权暂停/恢复
                        if clientsBool then
                            acountSuspend = acountSuspend + 1
                            if acountSuspend % 2 == 0 then
                                action = false
                            else
                                action = true
                            end
                            registerTask.PauseResumeServiceTask(action)
                        end
                    elseif todo == "authorize" then -- 授权申请/更新
                        if clientsBool then
                            registerTask.AuthorizationApplicationUpdateServiceTask()
                        end
                    elseif todo == "cancelAuth" then -- 授权撤销
                        if clientsBool then
                            registerTask.AuthorizationRevocationServiceTask()
                        end
                    elseif todo == "getTokenInfo" then -- 授权查询
                        if clientsBool then
                            registerTask.AuthorizationQueryServiceTask()
                        end
                    elseif todo == "reboot" then -- 设备重启
                        if clientsBool then
                            sys.taskInit(deviceRestart.restartDevice)
                        end
                    elseif todo == "status" then -- 设备在线状态查询
                        deviceOnlineCheck.CheckDeviceOnline()
                    elseif todo == "resetAll" then -- 重置注册中心参数
                        batchSetParameters.BatchResetcenterConfigParam()
                    elseif todo == "batch" then -- 批量设参
                        if clientsBool then
                            local batchParam, batchVal =
                                tjsondata["batchParam"], tjsondata["batchVal"]
                            sys.taskInit(batchSetParameters.SetParamBatch,
                                         batchParam, batchVal)
                        end
                    end
                else
                    sysTime = utilsBySelf.GetSystemTime()
                    errInfo = errInfo .. "[" .. sysTime .. "]" ..
                                  "[json.decode error:]" .. errinfo .. "\n"
                    print("json.decode error", errinfo)
                end
            elseif isContainTopic(data.topic) then
                if resultMqtt and type(tjsondata) == "table" then
                    todo, exercise = tjsondata["todo"], tjsondata["exercise"]
                    if tjsondata["2"] then
                        msgCode = tjsondata["2"]
                    end
                    if tjsondata["16"] then
                        msgCode = tjsondata["16"]
                    end
                    log.info("msgCode", msgCode)
                    log.info("exercise:", exercise, "regCenter:", not regCenter,
                             "msgCode:", msgCode)
                    if exercise then -- 预警演练（云）
                        unitId = tonumber(tjsondata["13"])
                        if unitId == orgId then
                            earthquakeWaringDril.EarthquakeWarningDrillSystem(
                                tjsondata, "keson","")
                        end
                    end
                    if msgCode == "0199" then -- 单位预警取消（包含演习及模拟）
                        unitId = tonumber(tjsondata["17"])
                        if unitId == orgId then
                            earthquakeWaringDril.EarthquakeWarningDrillSystem(
                                tjsondata, "keson","")
                            earthquakeWaring.EarthquakeWarning(aesDecryptMsg,
                                                               tjsondata,
                                                               data.topic)
                        else
                            sysTime = utilsBySelf.GetSystemTime()
                            errInfo = errInfo .. "[" .. sysTime .. "]" ..
                                          "[错误信息:]所属部门ID不相符！\n"
                        end
                    end
                    if regCenter == "false" then
                        if msgCode == "0201" or msgCode == "0202" then -- 模拟地震预警（本地）
                            unitId = tonumber(tjsondata["17"])
                            if unitId == orgId then
                                earthquakeWaring.EarthquakeWarning(
                                    aesDecryptMsg, tjsondata, data.topic)
                            end
                        elseif msgCode == "0101" or msgCode == "0102" then
                            earthquakeWaring.EarthquakeWarning(aesDecryptMsg,
                                                               tjsondata,
                                                               data.topic)
                        end
                    end
                end
            elseif data.topic == "yunnan/orgInfo/get/" .. clientNo then -- 云南设备单位信息请求更新
                if resultMqtt and type(tjsondata) == "table" then
                    orgId = tjsondata["orgId"]
                    log.info("orgId:", orgId)
                    http.request("GET",
                                 "http://47.104.194.249:8098/quake/old/organization/" ..
                                     orgId, nil, nil, nil, nil, cbFnc)
                end
            else
                sysTime = utilsBySelf.GetSystemTime()
                errInfo = errInfo .. "[" .. sysTime .. "]" ..
                              "[订阅主题满足要求:]" ..
                              "接收的主题:" .. data.topic .. "\n"
                logGenerator.generateLogTask(errInfo, "log")
            end
        else
            break
        end
    end
    log.info("MQTT TASK RESULT", result, "MQTT TASK DATA", data)
    return result or data == "timeout" or data == "APP_SOCKET_SEND_DATA"
end
